package com.ccp.dev.extend.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.util.AppUtil;
import com.ccp.dev.core.util.FileUtil;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.core.util.ZipUtil;
import com.ccp.dev.system.consts.SecretUtil;
import com.ccp.dev.system.dao.DictionaryDao;
import com.ccp.dev.system.dao.GlobalTypeDao;
import com.ccp.dev.system.dao.SysFileDao;
import com.ccp.dev.system.model.Dictionary;
import com.ccp.dev.system.model.GlobalType;
import com.ccp.dev.system.model.SysFile;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.system.service.SysFileService;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipInputStream;


/**
 * 扩展的SYS_FILE service类
 *
 * @author 创新中心-王明亮
 */
@Service
public class ExtendSysFileService extends BaseService<SysFile> {

    @Resource
    private SysFileDao dao;
    @Resource
    private DictionaryDao dictionaryDao;
    @Resource
    private GlobalTypeDao globalTypeDao;

    private static final int BUFFER = 8192;

    /**
     * 获取当前时间
     *
     * @return
     */
    private static String getNowStr() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date());
    }

    /**
     * 设置压缩编码，解决中文文件名乱码问题
     */
    private static final String encoding = System.getProperty("sun.jnu.encoding");

    static {
        /**
         * 解压依据的编码是sun.zip.encoding 所以需要设置 解压编码
         */
        System.setProperty("sun.zip.encoding", encoding);
    }


    /**
     * 配置压缩属性
     *
     * @param out
     */
    private static void configCompressProperties(ZipOutputStream out) {
        //设置文件名编码方式
        out.setEncoding(encoding);
        //设置压缩说明
        out.setComment("\n压缩时间：" + getNowStr() + " \n");
    }

    /**
     * Zip压缩文件或者文件夹
     *
     * @param srcPathName 待压缩文件或者文件夹路径
     * @param zipFileName 压缩后压缩文件存放路径
     */
    public static void compress(String srcPathName, String zipFileName) {
        File file = new File(srcPathName);
        File zipFile = new File(zipFileName);
        if (!file.exists()) {
            throw new RuntimeException(srcPathName + "不存在！");
        }
        boolean isSuccessful = true;
        ZipOutputStream out = null;
        try {
            CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32());
            out = new ZipOutputStream(cos);
            //配置压缩属性
            configCompressProperties(out);
            //执行压缩
            doCompress(file, out, "");
        } catch (Exception e) {
            isSuccessful = false;
            throw new RuntimeException(e);
        } finally {
            closeResource(out);
        }
    }

    /**
     * 释放资源
     *
     * @param resources
     */
    private static void closeResource(Closeable... resources) {
        if (resources == null || resources.length < 1) {
            return;
        }
        for (Closeable cur : resources) {
            if (cur == null) {
                continue;
            }
            if (cur instanceof ZipInputStream) {
                ZipInputStream zis = (ZipInputStream) cur;
                try {
                    zis.closeEntry();
                } catch (IOException e) {
                }
            }
            if (cur instanceof ZipOutputStream) {
                ZipOutputStream zos = (ZipOutputStream) cur;
                try {
                    zos.closeEntry();
                } catch (IOException e) {
                }
            }
            try {
                cur.close();
            } catch (IOException e) {
            }
        }
    }


    /**
     * 执行压缩
     *
     * @param file    压缩文件/文件夹
     * @param out
     * @param basedir 输出文件地址
     */
    private static void doCompress(File file, ZipOutputStream out, String basedir) {
        if (!file.exists()) {
            return;
        }
        if (file.isDirectory()) {
            //压缩目录
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                doCompress(files[i], out, basedir + file.getName() + "/");
            }
            // 空文件夹的处理
            try {
                out.putNextEntry(new ZipEntry(basedir + file.getName() + "/"));
            } catch (Exception e) {

            }
        } else {
            //压缩文件
            BufferedInputStream bis = null;
            try {
                bis = new BufferedInputStream(new FileInputStream(file));
                ZipEntry entry = new ZipEntry(basedir + file.getName());
                out.putNextEntry(entry);
                int count;
                byte data[] = new byte[BUFFER];
                while ((count = bis.read(data, 0, BUFFER)) != -1) {
                    out.write(data, 0, count);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                closeResource(bis);
            }
        }
    }


    /**
     * 下载文件
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @param fileId   文件id
     * @throws IOException 抛出异常
     */
    public void downloadFile(HttpServletRequest request, HttpServletResponse response, String fileId) throws Exception {
        Map<String, Object> map = this.check(fileId);
        if (!"200".equals(map.get("code").toString())) {
            this.setresponse(response, map.get("message").toString());
        } else {
            SysFile sysFile = (SysFile) map.get("sysFile");
            // 获取完整名称
            String fileName = sysFile.getFileName()
                    +getSecText(sysFile.getFileLevel()+"")
                    + "." + sysFile.getExt();
            String saveType = SysFileService.getSaveType();

            String attachPath = SysFileService.getBasePath().replace("/", File.separator);
            // 如果附件保存到数据库中
            if (saveType.equals(SysFile.SAVETYPE_DATABASE) && null != sysFile.getFileBlob()) {
                FileUtil.downLoadFileByByte(request, response, sysFile.getFileBlob(), fileName);
            } else {
                String filePath = sysFile.getFilePath();
//				if (StringUtil.isEmpty(filePath)) {
//					return;
//				}
                if (StringUtil.isEmpty(attachPath)) {
                    attachPath = AppUtil.getRealPath("/attachFiles/temp");
                }
                // 如果文件是加密过的
                if (SysFile.ENCRYPTED_YES == sysFile.getEncrypted()) {
                    // 原文件路径
                    String fullPath = StringUtil.trimSufffix(attachPath, File.separator) + File.separator
                            + filePath.replace("/", File.separator);
                    // 暂时解压路径
                    String pathToUnZip = StringUtil.trimSufffix(attachPath, File.separator) + File.separator
                            + sysFile.getFileId();
                    ZipUtil.unZip(fullPath, pathToUnZip, SysFileService.getFilePassWord(sysFile.getCreator(), fileId));
                    // 解压后的文件路径
                    String pathAfterUnZip = pathToUnZip + File.separator + sysFile.getFileId() + "." + sysFile.getExt();
                    FileUtil.downLoadFile(request, response, pathAfterUnZip, fileName);
                    // 是否删除临时文件夹
//                FileUtil.deleteDir(new File(pathToUnZip));
                } else {
                    String fullPath = StringUtil.trimSufffix(attachPath, File.separator) + File.separator
                            + filePath.replace("/", File.separator);
                    FileUtil.downLoadFile(request, response, fullPath, fileName);
                }
            }
        }
    }

    /**
     * <p>
     * Description: 校验下载参数：因要返回给浏览器下载失败详细信息： 所有检验汇聚到这里，
     * </p>
     *
     * @Author mhc
     * @Time 2020年6月11日 上午10:57:10
     * @Version 1.0
     */
    private Map<String, Object> check(String fileId) {
        Map<String, Object> result = new HashMap<String, Object>();
//        result.put("code", "200");
//        if (StringUtil.isEmpty(fileId)) {
//            result.put("code", "400");
//            result.put("message", "请传递有效参数！");
//        }
//        SysFile sysFile = getOneById(fileId);
//        if (sysFile == null) {
//            result.put("code", "400");
//            result.put("message", "请传递有效参数！");
//        }
//        if (!this.checkLevel(sysFile.getFileLevel())) {
//            result.put("code", "403");
//            result.put("message", "权限不足！");
//        }
//        String filePath = sysFile.getFilePath();
//        if (StringUtil.isEmpty(filePath)) {
//            result.put("code", "400");
//            result.put("message", "文件路径不存在！");
//        }
        result.put("code", "200");
        SysFile sysFile = getOneById(fileId);
        result.put("sysFile", sysFile);
        return result;

    }

    // 检验下载密级
    private boolean checkLevel(int level) {
        // 检验密级是否合法
        SysUser sysUser = (SysUser) ContextUtil.getCurrentUser();
        if (null == sysUser) {
            return false;
        }
        return SecretUtil.getUserDataSecretMap().get(sysUser.getPrivacyLevel()) >= level;
    }

    // 下载错误历史提示界面
    private void setresponse(HttpServletResponse response, String message) {
        try {
            response.setHeader("Content-Type", "text/html;charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            PrintWriter writer = response.getWriter();
            writer.print("<!DOCTYPE html>\r\n" + "<html lang=\"en\">\r\n" + "<head>\r\n"
                    + "    <meta charset=\"UTF-8\">\r\n" + "    <title>Title</title>\r\n" + "    <style>\r\n"
                    + "        *{\r\n" + "            margin:0;\r\n" + "            padding:0;\r\n" + "\r\n"
                    + "        }\r\n" + "        html,body{\r\n" + "            height:100%;\r\n"
                    + "            width:100%\r\n" + "        }\r\n" + "        #show{\r\n"
                    + "            width: 300px;\r\n" + "            height: 260px;\r\n"
                    + "            background-color: #fff;\r\n" + "            position: absolute;\r\n"
                    + "            transform: translate(-50%,-50%);\r\n" + "            left: 50%;\r\n"
                    + "            top: 50%;\r\n" + "        }\r\n" + "    </style>\r\n" + "</head>\r\n" + "<body>\r\n"
                    + "<div id='main' style=\"width:100%;height:100%;opacity: 0.6;background-color:black\">\r\n"
                    + "    <div id=\"show\">\r\n"
                    + "        <div style=\"height:36px;line-height:36px;background-color: #716A6A\">\r\n"
                    + "            <span style=\"float: left;margin-left:10px;color:#fff\">响应信息</span>\r\n"
                    + "            <span id='close' style=\"float: right;margin-right: 10px;font-size: 23px;color: #fff;cursor:pointer;\">x</span>\r\n"
                    + "        </div>\r\n" + "        <div>" + message + "</div>\r\n" + "    </div>\r\n" + "</div>\r\n"
                    + "<script>\r\n" + "\r\n" + "        document.getElementById('close').onclick=function(){\r\n"
                    + "            document.getElementById('main').style.display='none'\r\n" + "        }\r\n"
                    + "</script>\r\n" + "</body>\r\n" + "</html>");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据分类表的nodekey获取数据字典数据。
     *
     * @param nodeKey 节点key
     *
     * @return 数据字典数据
     */
    public List<Dictionary> getDicByNodeKey(String nodeKey) {
        GlobalType globalType = globalTypeDao.getByDictNodeKey(nodeKey);
        if (globalType == null) {
            return new ArrayList<>();
        }
        String typeId = globalType.getTypeId();
        List<Dictionary> dictionaries = dictionaryDao.getByTypeId(typeId);
        return dictionaries;
    }

    private String getSecText(String fileLevel){
        String fileLevelText="";
        List<Dictionary> secDic=getDicByNodeKey("mj");
        for (Dictionary sec: secDic) {
            if (sec.getItemValue().equals(fileLevel)){
                fileLevelText="("+sec.getItemName()+")";
                return fileLevelText;
            }
        }
        return fileLevelText;
    }

    public int updateFileLevel(SysFile[] files) {
        int result=0;
        for (int i = 0; i < files.length; i++) {
            SysFile sysFile = getOneById(files[i].getFileId());
            sysFile.setFileLevel(files[i].getFileLevel());
            dao.update(sysFile);
            result+=1;
        }
        return result;
    }
}
